package com.bci.internal.engine.bcibpmengine.exception;


import com.bci.internal.engine.bcibpmengine.support.RestResult;
import com.fasterxml.jackson.core.JsonProcessingException;
import lombok.extern.slf4j.Slf4j;
import org.activiti.engine.ActivitiException;
import org.springframework.http.HttpStatus;
import org.springframework.remoting.RemoteAccessException;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolationException;
import java.security.GeneralSecurityException;

/**返回自定义的异常错误消息
 * @author jzwu
 * @since 2021/4/4 0004
 */
@Slf4j
@RestControllerAdvice(annotations = {Controller.class, RestController.class})
public class ControllerExceptionHandler {

    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public RestResult<?> handle(MethodArgumentNotValidException ex, HttpServletRequest request) {
        log.warn("无效的方法参数: {}", ex.getMessage());
        StringBuilder sb = new StringBuilder();
        ex.getBindingResult().getAllErrors().forEach(e -> sb.append(e.getDefaultMessage()).append(", "));
        if (sb.length() > 1) {
            sb.delete(sb.length() - 2, sb.length());
        }
        return RestResult.builder()
                .error("无效的方法参数")
                .message(sb.toString())
                .code(HttpStatus.BAD_REQUEST.value())
                .path(request.getServletPath())
                .verb(request.getMethod())
                .build();
    }

    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(ConstraintViolationException.class)
    public RestResult<?> handle(ConstraintViolationException ex, HttpServletRequest request) {
        log.warn("HTTP请求参数校验异常: {}", ex.getMessage());
        return RestResult.builder()
                .error("HTTP请求参数校验异常")
                .message(ex.getMessage())
                .code(HttpStatus.BAD_REQUEST.value())
                .path(request.getServletPath())
                .verb(request.getMethod())
                .build();
    }

    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(IllegalArgumentException.class)
    public RestResult<?> handle(IllegalArgumentException ex, HttpServletRequest request) {
        log.warn("非法的参数: {}", ex.getMessage());
        return RestResult.builder()
                .error("非法的参数")
                .message(ex.getMessage())
                .code(HttpStatus.BAD_REQUEST.value())
                .path(request.getServletPath())
                .verb(request.getMethod())
                .build();
    }

    @ResponseStatus(HttpStatus.FORBIDDEN)
    @ExceptionHandler(UnsupportedOperationException.class)
    public RestResult<?> handle(UnsupportedOperationException ex, HttpServletRequest request) {
        log.warn("无效的操作: {}", ex.getMessage());
        return RestResult.builder()
                .error("无效的操作")
                .message(ex.getMessage())
                .code(HttpStatus.FORBIDDEN.value())
                .path(request.getServletPath())
                .verb(request.getMethod())
                .build();
    }

    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(NullPointerException.class)
    public RestResult<?> handle(NullPointerException ex, HttpServletRequest request) {
        String err = String.format("%1s: %2s 出现空指针异常", request.getMethod(), request.getServletPath());
        log.error(err, ex);
        return RestResult.builder()
                .error("找不到对象")
                .message(ex.getMessage())
                .code(HttpStatus.INTERNAL_SERVER_ERROR.value())
                .path(request.getServletPath())
                .verb(request.getMethod())
                .build();
    }

    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(RemoteAccessException.class)
    public RestResult<?> handle(RemoteAccessException ex, HttpServletRequest request) {
        log.error("远程服务调用失败", ex);
        return RestResult.builder()
                .error("远程服务调用失败")
                .message(ex.getMessage())
                .code(HttpStatus.INTERNAL_SERVER_ERROR.value())
                .path(request.getServletPath())
                .verb(request.getMethod())
                .build();
    }

    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(JsonProcessingException.class)
    public RestResult<?> handle(JsonProcessingException ex, HttpServletRequest request) {
        log.error("序列化/反序列化失败", ex);
        return RestResult.builder()
                .error("序列化/反序列化失败")
                .message(ex.getMessage())
                .code(HttpStatus.INTERNAL_SERVER_ERROR.value())
                .path(request.getServletPath())
                .verb(request.getMethod())
                .build();
    }

    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(GeneralSecurityException.class)
    public RestResult<?> handle(GeneralSecurityException ex, HttpServletRequest request) {
        log.error("加密/解密失败, {}", ex.getMessage());
        return RestResult.builder()
                .error("加密/解密失败")
                .message(ex.getMessage())
                .code(HttpStatus.INTERNAL_SERVER_ERROR.value())
                .path(request.getServletPath())
                .verb(request.getMethod())
                .build();
    }

    @ExceptionHandler(ActivitiException.class)
    public RestResult<?> parsing(ActivitiException ex, HttpServletRequest request) {
        log.error("上传流程部署文件失败, {}", ex.getMessage());
        return RestResult.builder()
                .error("上传流程部署文件失败")
                .message(ex.getMessage())
                .code(HttpStatus.INTERNAL_SERVER_ERROR.value())
                .path(request.getServletPath())
                .verb(request.getMethod())
                .build();
    }
}
